import React, { useState, useEffect } from 'react'

const boxStyle = {
  margin: '10px',
  border: '1px solid #ccc',
  borderRadius: '10px',
}
const flexBox = {
  display: 'flex',
  justifyContent: 'space-around',
  flexWrap: 'wrap',
}

/* 
    首次挂在生命周期顺序
    constructor()
    static getDerivedStateFromProps()
    render()  接收的是最新的props和state
    componentDidMount()
*/

/* 
    当组件的 props 或 state 发生变化时会触发更新 生命周期顺序
    static getDerivedStateFromProps()
    shouldComponentUpdate()
    render() 接收的是最新的props和state
    getSnapshotBeforeUpdate()
    componentDidUpdate()
*/

// shouldComponentUpdate会使PureComponent失效
// React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。
// 组件接收this.props及时未使用,PureComponent下也会更新

// export class Son extends React.PureComponent {
export class Son extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      noSendState: 2,
      sendState: 4,
      flag: '1',
    }
    this.input = React.createRef()
    this.changenoSendState = this.changenoSendState.bind(this)
    this.changeSendState = this.changeSendState.bind(this)
    this.handleChange = this.handleChange.bind(this)
    console.log('Son---constructor', this.props, this.state)
  }

  // ++++++++++++++++++ 生命周期 ++++++++++
  componentDidMount() {
    console.log('Son----componentDidMount', this.props, this.state)
  }

  // 在getDerivedStateFromProps中不能使用this, props, state分别为最新值
  // 静态方法不能使用实例,故不可使用this.state, 无影响本身通过最新props和state参数,更改最终给render的this.props和state
  static getDerivedStateFromProps(props, state) {
    console.log('Son----getDerivedStateFromProps', props, state, this)
    if (state.noSendState > 5) {
      return {
        aaa: 1111,
      }
    }
    return null
  }

  // 根据 shouldComponentUpdate() 的返回值，判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染
  // 首次渲染或使用 forceUpdate() 时不会调用该方法。
  // 返回 false 并不会阻止子组件在 state 更改时重新渲染。
  shouldComponentUpdate(nextProps, nextState) {
    // nextProps, nextState 为造成重新渲染新值, this.props, this.state 取到的为旧的值
    console.log('Son----shouldComponentUpdate', nextProps, nextState, this.props, this.state)
    // return true
    return nextState.flag === '1' ? true : false
    // return this.input.current.value === '1' ? true : false
  }

  // render 函数

  // prevProps, prevState 为旧的值, 新值通过this.state, this.props直接获取
  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('son__getSnapshotBeforeUpdate', prevProps, prevState)
    return 111222333
  }

  // prevProps, prevState 为旧的值, 新值通过this.state, this.props直接获取 snapshot为 getSnapshotBeforeUpdate生命周期中返回值
  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('Son----componentDidUpdate', prevProps, prevState, snapshot, this.props, this.state)
  }

  // ++++++++++++++++++++++ 函数 +++++++++++
  changenoSendState() {
    // console.log(this.input, this.input.current.value)
    console.log(11111, this.state)
    this.setState({
      noSendState: this.state.noSendState + 1,
    })
  }
  changeSendState() {
    console.log(222222, this.state)
    this.setState({
      sendState: this.state.sendState + 1,
    })
  }
  handleChange(event) {
    // event为react的合成事件
    console.log('handleChange...', event.target.value)
    this.setState({ flag: event.target.value })
  }
  render() {
    console.log('Son----render', this.props, this.state)
    return (
      <div style={boxStyle}>
        <p>这是Son组件</p>
        <p>接收值:{}</p>

        {/* 受控组件 */}
        {/* 受控组件 不正常刷新会失效 请勿这样操作 */}
        {true && (
          <div style={flexBox} className="checkbox">
            <label>
              受控组件是否更新:
              <select value={this.state.flag} onChange={this.handleChange}>
                <option value="1">是</option>
                <option value="0">否</option>
              </select>
            </label>
            <p>受控---当前是否更新:{this.state.flag === '1' ? '是' : '否'}</p>
          </div>
        )}

        {/* 非受控组件 */}
        {false && (
          <div style={flexBox} className="checkbox">
            <label>
              非受控组件是否更新:
              <select defaultValue="1" ref={this.input}>
                <option value="1">是</option>
                <option value="0">否</option>
              </select>
            </label>
            {/* 不推荐在render中直接使用ref.current.value等值, 各种情况中可能为null */}
            {/* render执行后为pre-commit阶段, getSnapshotBeforeUpdate后会commit才会通过虚拟dom更新dom树,更新refs */}
            {this.input && this.input.current && <p>非受控组件更新:{this.input.current.value}</p>}
          </div>
        )}

        <div style={flexBox}>
          <button style={{ marginBottom: '10px' }} onClick={this.changenoSendState}>
            son不传递的state: {this.state.noSendState}
          </button>
          <br />
          <button style={{ marginBottom: '10px' }} onClick={this.changeSendState}>
            son传递的state: {this.state.sendState}
          </button>
        </div>
        <Sson />
      </div>
    )
  }
}

export class Sson extends React.Component {
  constructor(props) {
    super(props)
    console.log('Sson---constructor', this.props, this.state)
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log(
      'Sson----componentDidUpdate',
      prevProps,
      prevState,
      snapshot,
      this.props,
      this.state
    )
  }

  render() {
    return <p style={boxStyle}>这是孙子组件</p>
  }
}
